# Makefile for Go benchmark testing and visualization

.PHONY: help install-tools bench bench-json web clean all compare setup

# 默认目标
.DEFAULT_GOAL := help

# 变量定义
TEST_PATTERN ?= .
BENCH_PATTERN ?= .
BENCH_COUNT ?= 5
BENCH_TIME ?= 10s
PORT ?= 8080
REPORT_DIR ?= reporter
BENCH_FILE := bench_results.txt
BENCH_JSON := ./benchmarks.json
OLD_BENCH := old_bench.txt
NEW_BENCH := new_bench.txt
TEMPLATE_FILE := benchmark-template.html

# 颜色定义
GREEN := \033[32m
YELLOW := \033[33m
BLUE := \033[34m
RESET := \033[0m

help: ## 显示帮助信息
	@echo "$(BLUE)Go Benchmark Testing and Visualization$(RESET)"
	@echo "========================================"
	@echo ""
	@echo "$(GREEN)Available targets:$(RESET)"
	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "  $(YELLOW)%-15s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
	@echo ""
	@echo "$(GREEN)Variables:$(RESET)"
	@echo "  $(YELLOW)BENCH_PATTERN$(RESET)  Benchmark pattern (default: .)"
	@echo "  $(YELLOW)BENCH_COUNT$(RESET)    Number of runs (default: 5)"
	@echo "  $(YELLOW)BENCH_TIME$(RESET)     Benchmark time (default: 10s)"
	@echo "  $(YELLOW)PORT$(RESET)           Web server port (default: 8080)"
	@echo ""
	@echo "$(GREEN)Example usage:$(RESET)"
	@echo "  make bench BENCH_PATTERN=BenchmarkFibonacci"
	@echo "  make web PORT=9090"
	@echo "  make all BENCH_COUNT=10"

setup: ## 创建必要的目录和配置
	@echo "$(GREEN)Setting up project structure...$(RESET)"
	@mkdir -p benchmarks
	@mkdir -p reports
	@touch .gitignore
	@grep -q "bench_results.txt" .gitignore || echo "bench_results.txt" >> .gitignore
	@grep -q "*.json" .gitignore || echo "*.json" >> .gitignore
	@grep -q "reports/" .gitignore || echo "reports/" >> .gitignore
	@echo "$(GREEN)Setup completed!$(RESET)"

install-tools: ## 安装必要的工具
	@echo "$(GREEN)Installing benchmark tools...$(RESET)"
	@echo "Installing gobenchdata..."
	@go install go.bobheadxi.dev/gobenchdata@latest
	@echo "Installing benchstat..."
	@go install golang.org/x/perf/cmd/benchstat@latest
	@echo "$(GREEN)Tools installed successfully!$(RESET)"

check-tools: ## 检查工具是否已安装
	@echo "$(GREEN)Checking required tools...$(RESET)"
	@which gobenchdata > /dev/null || (echo "$(YELLOW)gobenchdata not found. Run 'make install-tools'$(RESET)" && exit 1)
	@which benchstat > /dev/null || (echo "$(YELLOW)benchstat not found. Run 'make install-tools'$(RESET)" && exit 1)
	@echo "$(GREEN)All tools are available!$(RESET)"

test: test-unit ## 默认运行单元测试

test-unit: ## 只运行单元测试（跳过基准测试）
	@echo "$(GREEN)Running unit tests...$(RESET)"
	@echo "Pattern: $(TEST_PATTERN)"
	@echo ""
	@go test -v -run=$(TEST_PATTERN)

test-unit-quiet: ## 安静模式运行单元测试
	@echo "$(GREEN)Running unit tests (quiet mode)...$(RESET)"
	@go test -run=$(TEST_PATTERN)

bench-fast: check-tools ## 快速基准测试（小参数）
	@echo "$(GREEN)Running fast benchmarks...$(RESET)"
	@go test -timeout=30s -run=^$$ -bench=$(BENCH_PATTERN) -benchmem -benchtime=1s | tee $(BENCH_FILE)

bench-medium: check-tools ## 中等基准测试
	@echo "$(GREEN)Running medium benchmarks...$(RESET)"
	@go test -timeout=60s -run=^$$ -bench=$(BENCH_PATTERN) -benchmem -benchtime=3s | tee $(BENCH_FILE)

bench-stress: check-tools ## 压力基准测试（大参数）
	@echo "$(GREEN)Running stress benchmarks...$(RESET)"
	@echo "$(YELLOW)This may take several minutes...$(RESET)"
	@go test -timeout=300s -run=^$$ -bench=$(BENCH_PATTERN) -benchmem -benchtime=5s | tee $(BENCH_FILE)

bench-short: check-tools ## 短模式基准测试
	@echo "$(GREEN)Running short benchmarks...$(RESET)"
	@go test -short -timeout=15s -run=^$$ -bench=$(BENCH_PATTERN) -benchmem -benchtime=500ms | tee $(BENCH_FILE)

# 更新默认的bench目标
bench: bench-fast ## 默认运行快速基准测试

bench-json: ## 生成 JSON
	@echo "$(GREEN)Converting results to JSON...$(RESET)"
	@cat $(BENCH_FILE) | gobenchdata --json $(BENCH_JSON)
	@echo "$(GREEN)JSON data saved to $(BENCH_JSON)$(RESET)"

web: ## 启动 Web 界面查看结果
	@if [ ! -f $(BENCH_JSON) ]; then \
		echo "$(YELLOW)No benchmark data found. Running benchmark first...$(RESET)"; \
		make bench-json; \
		mkdir -p $(REPORT_DIR) && cp $(BENCH_JSON) $(REPORT_DIR);\
		cp $(TEMPLATE_FILE) $(REPORT_DIR)/index.html; \
	fi
	@echo "$(GREEN)Starting web server on port $(PORT)...$(RESET)"
	@echo "$(BLUE)Open http://localhost:$(PORT) in your browser$(RESET)"
	@echo "$(YELLOW)Press Ctrl+C to stop the server$(RESET)"
# 	@gobenchdata web generate $(REPORT_DIR)
	@cd $(REPORT_DIR) && python3 -m http.server $(PORT) 

web-background: ## 在后台启动 Web 界面
	@if [ ! -f $(BENCH_JSON) ]; then \
		echo "$(YELLOW)No benchmark data found. Running benchmark first...$(RESET)"; \
		make bench-json; \
		mkdir -p $(REPORT_DIR) && cp $(BENCH_JSON) $(REPORT_DIR); \
		cp $(TEMPLATE_FILE) $(REPORT_DIR)/index.html; \
	fi
	@echo "$(GREEN)Starting web server in background on port $(PORT)...$(RESET)"
	@echo "$(BLUE)Open http://localhost:$(PORT) in your browser$(RESET)"
# 	@gobenchdata web generate $(REPORT_DIR)
	@cd $(REPORT_DIR) && python3 -m http.server $(PORT) > ../server.log 2>&1 & echo $$! > ../web.pid
	@echo "$(GREEN)Web server started! PID saved to web.pid$(RESET)"

stop-web: ## 停止后台 Web 服务器
	@if [ -f web.pid ]; then \
		kill `cat web.pid` && rm web.pid && echo "$(GREEN)Web server stopped$(RESET)"; \
	else \
		echo "$(YELLOW)No web server PID found$(RESET)"; \
	fi

stats: ## 显示基准测试统计信息
	@if [ ! -f $(BENCH_FILE) ]; then \
		echo "$(YELLOW)No benchmark results found. Run 'make bench' first$(RESET)"; \
		exit 1; \
	fi
	@echo "$(GREEN)Benchmark Statistics:$(RESET)"
	@echo "====================="
	@benchstat $(BENCH_FILE)

compare: ## 比较两次基准测试结果
	@if [ ! -f $(OLD_BENCH) ] || [ ! -f $(NEW_BENCH) ]; then \
		echo "$(YELLOW)Comparison files not found.$(RESET)"; \
		echo "Please ensure $(OLD_BENCH) and $(NEW_BENCH) exist"; \
		echo "You can create them by running:"; \
		echo "  cp $(BENCH_FILE) $(OLD_BENCH)"; \
		echo "  # make changes to your code"; \
		echo "  make bench && cp $(BENCH_FILE) $(NEW_BENCH)"; \
		exit 1; \
	fi
	@echo "$(GREEN)Comparing benchmark results...$(RESET)"
	@benchstat $(OLD_BENCH) $(NEW_BENCH)

save-baseline: ## 保存当前结果作为基准
	@if [ ! -f $(BENCH_FILE) ]; then \
		echo "$(YELLOW)No benchmark results found. Run 'make bench' first$(RESET)"; \
		exit 1; \
	fi
	@cp $(BENCH_FILE) $(OLD_BENCH)
	@echo "$(GREEN)Baseline saved to $(OLD_BENCH)$(RESET)"

compare-with-baseline: bench save-new-results ## 与基准进行比较
	@make compare

save-new-results: ## 保存当前结果作为新结果
	@if [ ! -f $(BENCH_FILE) ]; then \
		echo "$(YELLOW)No benchmark results found. Run 'make bench' first$(RESET)"; \
		exit 1; \
	fi
	@cp $(BENCH_FILE) $(NEW_BENCH)
	@echo "$(GREEN)New results saved to $(NEW_BENCH)$(RESET)"

all: bench-json stats web ## 运行完整的基准测试流程

clean: ## 清理生成的文件
	@echo "$(GREEN)Cleaning up...$(RESET)"
	@rm -f $(BENCH_FILE) $(BENCH_JSON) $(OLD_BENCH) $(NEW_BENCH)
	@rm -f web.pid
	@rm -rf reports/
	@echo "$(GREEN)Cleanup completed!$(RESET)"

profile: ## 运行带性能分析的基准测试
	@echo "$(GREEN)Running benchmark with profiling...$(RESET)"
	@go test -bench=$(BENCH_PATTERN) -benchmem -cpuprofile=cpu.prof -memprofile=mem.prof
	@echo "$(GREEN)Profile files generated: cpu.prof, mem.prof$(RESET)"
	@echo "$(BLUE)View CPU profile: go tool pprof cpu.prof$(RESET)"
	@echo "$(BLUE)View memory profile: go tool pprof mem.prof$(RESET)"

watch: ## 监控文件变化并自动运行基准测试
	@echo "$(GREEN)Watching for file changes...$(RESET)"
	@echo "$(YELLOW)Install 'entr' tool first: apt-get install entr$(RESET)"
	@find . -name "*.go" | entr -r make bench-quick

# 高级目标
continuous: ## 持续基准测试（每30秒运行一次）
	@echo "$(GREEN)Starting continuous benchmarking...$(RESET)"
	@echo "$(YELLOW)Press Ctrl+C to stop$(RESET)"
	@while true; do \
		make bench-quick; \
		sleep 30; \
	done

docker-bench: ## 在 Docker 中运行基准测试
	@echo "$(GREEN)Running benchmarks in Docker...$(RESET)"
	@docker run --rm -v $(PWD):/app -w /app golang:latest make bench

# 特殊的基准测试目标
bench-memory: ## 专注于内存使用的基准测试
	@echo "$(GREEN)Running memory-focused benchmarks...$(RESET)"
	@go test -bench=$(BENCH_PATTERN) -benchmem -memprofile=mem.prof | tee mem_bench.txt
	@echo "$(GREEN)Memory benchmark completed!$(RESET)"

bench-cpu: ## 专注于 CPU 使用的基准测试
	@echo "$(GREEN)Running CPU-focused benchmarks...$(RESET)"
	@go test -bench=$(BENCH_PATTERN) -cpuprofile=cpu.prof | tee cpu_bench.txt
	@echo "$(GREEN)CPU benchmark completed!$(RESET)"
